package com.justgame.project.cloud.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justgame.project.cloud.common.constant.Const;
import com.justgame.project.cloud.common.constant.Result;
import com.justgame.project.cloud.common.util.RedisUtil;
import com.justgame.project.cloud.common.util.TokenUtil;
import com.justgame.project.cloud.gateway.provider.AuthProvider;
import com.justgame.project.cloud.gateway.provider.RequestProvider;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Set;

/**
 * 网关鉴权
 * @author ZhouWeiBo
 * @create 2022/3/15
 */
@Component
@AllArgsConstructor
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {
    private final ObjectMapper objectMapper;
    private final RedisUtil redisUtil;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final static String EMPTY_URL = "/";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 校验 Token 放行
        String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange);
        String path = exchange.getRequest().getURI().getPath();
        // 拒绝空路径访问
        if (StringUtils.isBlank(originalRequestUrl) || StringUtils.isBlank(path) ||
                EMPTY_URL.equals(originalRequestUrl) || EMPTY_URL.equals(path)){
           return unPass(exchange,Result.fail("无效的请求路径",404));
        }
        /* 获取所有的请求路径信息 */
        Set<String> paths = redisUtil.sGet(Const.KEY_REDIS_API);
        /* 如果不存在这个路径的api接口则直接在网关层拒绝访问 */
        if (!paths.contains(originalRequestUrl) && !paths.contains(path)){
           return unPass(exchange,Result.fail("未找到路径:"+originalRequestUrl,404));
        }

        /* 访问的是白名单接口，放行 */
        if (isSkipFilter(originalRequestUrl) && isSkipFilter(path)){
            return chain.filter(exchange);
        }
        /* 获取token */
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if (StringUtils.isBlank(token)){
            /* 无token访问需要权限的接口，则拒绝提供服务！ */
            return unPass(exchange,Result.fail(Const.CODE_TOKEN_EMPTY_CHINESE, Const.CODE_TOKEN_EMPTY));
        }

        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            System.out.println("看看啥时候完成");
        }));
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    private boolean isSkipFilter(String path){
        return !AuthProvider.getAuthListUrl().stream().allMatch( pattern -> antPathMatcher.match(pattern,path) );
    }

    private Mono<Void> unPass(ServerWebExchange exchange, Result<?> result){
        ServerHttpResponse resp = exchange.getResponse();
        resp.setStatusCode(HttpStatus.BAD_REQUEST);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String resultStr = "";
        try {
            resultStr = objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
        }
        DataBuffer dbf = resp.bufferFactory().wrap(resultStr.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(dbf));
    }
}
